package cn.com.cetccst.onlinecert;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

import cn.com.cetccst.skf.P10CSRGenerator;
import cn.com.cetccst.skf.SkfManager;

public class OnlineCertManager {

    private static final String TAG = "OnlineCertManager";

    //证书相关网络请求抽象
    private ICertRequester mCertRequester;

    //todo 考虑使用livedata做监听
    private List<ICertStatusListener> mCertStatusListeners;

    private CertStatus mCertStatus; //本地证书状态
    private boolean isOnlineCertEnabled; //后端在线发证开关状态
    private Handler mMainHandler;
    private boolean isNeedRestart = false;

    private OnlineCertManager() {
        mCertStatusListeners = new ArrayList<>();
        mMainHandler = new Handler(Looper.getMainLooper());
        mCertStatus = CertStatus.valueOf(0);//todo 使用kv持久化的状态做初始化
        isOnlineCertEnabled = true;//todo 使用kv持久化的状态做初始化
    }

    //证书状态枚举
    public enum CertStatus {
        Normal, Empty, Broken, Expired;

        public static CertStatus valueOf(int ordinal) {
            for (CertStatus status : CertStatus.values()) {
                if (ordinal == status.ordinal()) {
                    return status;
                }
            }
            return Empty;
        }
    }

    public interface ICertStatusListener {
        void onCertStatusChanged(boolean enabled, CertStatus certStatus);
    }

    static class SingletonHolder {
        static OnlineCertManager instance = new OnlineCertManager();
    }

    public static OnlineCertManager getInstance() {
        return OnlineCertManager.SingletonHolder.instance;
    }

    private void setRequester(ICertRequester requester) {
        this.mCertRequester = requester;
    }

    public boolean isOnlineCertEnabled() {
        return isOnlineCertEnabled;
    }

    public boolean isNeedRestart() {
        return isNeedRestart;
    }

    public CertStatus getCertStatus() {
        return mCertStatus;
    }

    private boolean isEnrolled() {
        return true;//todo 使用已持久化的真正的激活状态
    }

    //远端在线发证开关状态变更
    public void changeStatus(boolean enabled) {
        isOnlineCertEnabled = enabled;
        if (isEnrolled()) {
            isNeedRestart = true;
        }

        //todo KVManager 保存新的isOnlineCertEnabled状态。
        notifyStatusChanged(enabled);
    }

    public void notifyStatusChanged(boolean enabled) {
        mMainHandler.post(() -> {
            for (ICertStatusListener listener : mCertStatusListeners) {
                if (listener != null) {
                    listener.onCertStatusChanged(enabled, mCertStatus);
                }
            }
        });
    }

    public void requestCert(ICertRequestCallback<Boolean> callback) {
        String pk = getPublicKey();
        getPKCS10((p10 -> {
            mCertRequester.requestCert(pk, p10, (result, msg) -> {
                if (!TextUtils.isEmpty(result)) {
                    if (saveCert(result)) {
                        changeCertStatus(CertStatus.Normal);
                        callback.onResult(true, "");
                    } else {
                        callback.onResult(false, "证书保存失败");
                    }
                } else {
                    callback.onResult(false, msg);
                }
            });
        }));
    }

    public void changeCertStatus(CertStatus status) {
        if (mCertStatus != status) {
            mCertStatus = status;
            //todo save to kv
//            PrefStore.setIntValue(SsoApplication.getInstance(), "caStatus", CertStatus.ordinal());
        }
        checkLocalCertStatus();
    }

    private boolean checkLocalCertStatus() {
        //todo 检查本地证书状态
        return true;
    }

    private boolean saveCert(String resp) {
        try {
            JSONObject body = new JSONObject(resp);
            String signCert = body.optString("signCert");
            JSONObject encCert = body.optJSONObject("encCert");
            String cert = encCert.optString("cert");
            String workKey = encCert.optString("workKey");
            byte[] workKeyByte = Base64.decode(workKey, Base64.DEFAULT);
            SkfManager.getInstance().getSkfEntry().importCert(Base64.decode(cert, Base64.DEFAULT), false);
            SkfManager.getInstance().getSkfEntry().importKeyPair(workKeyByte);
            return SkfManager.getInstance().getSkfEntry().importCert(Base64.decode(signCert, Base64.DEFAULT), true);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        Log.e(TAG, "import Cert Failed");
        return false;
    }

    public void getPKCS10(P10CSRGenerator.P10RequestCallback callback) {
        mCertRequester.getUserInfo((result, msg) -> generatePKCS10(result, callback));
    }

    private void generatePKCS10(MdmUserInfo info, P10CSRGenerator.P10RequestCallback callback) {
        try {
            if (info == null) {
                Log.e(TAG, "can not generate pkcs10 for null user");
                callback.onGenP10Result("");
                return;
            }
            byte[] pkcs10 = SkfManager.getInstance().getSkfEntry().genPKCS10(info);
            if (pkcs10 == null) {
                Log.e(TAG, "got a null pkcs10");
                callback.onGenP10Result("");
            } else {
                callback.onGenP10Result(Base64.encodeToString(pkcs10, Base64.NO_WRAP));
            }
        } catch (Exception e) {
            Log.e(TAG, "generatePKCS10 got an Exception :", e);
            callback.onGenP10Result("");
        }
    }

    public String getPublicKey() {
        try {
            byte[] signPK = SkfManager.getInstance().getSkfEntry().getPublicKey(true);
            if (signPK == null) {
                Log.e(TAG, "got a null sign public key");
                return "";
            }
            return Base64.encodeToString(signPK, Base64.NO_WRAP);
        } catch (Exception e) {
            Log.e(TAG, "sign public key got an Exception :", e);
        }
        return "";
    }
}
